#include <stdio.h>
#include <string.h>
#include "argproc.h"


#define  __VEC_SECTOR 20

gboolean      build_arg(gint *argc, gchar ***argv, ...)
{
  va_list ap;
  const  gchar *key, *val;
  gchar **tmp;
  gint len = 0, i;

  if(! argc || ! argv)
	return FALSE;
  if(*argc == 0 || *argv == NULL)  {
	*argc = 0;
	*argv = g_new0(char *, __VEC_SECTOR);
	len += __VEC_SECTOR;
  }else  {
	tmp = g_new0(char *, *argc + __VEC_SECTOR);
	for(i = 0; i < *argc; i++)
	  *(tmp + i) = g_strdup(*(*argv + i));
	*argv = tmp;
	len = *argc + __VEC_SECTOR;
  }

  va_start(ap, argv);
  while(key = va_arg(ap, const gchar *))  {
	val = va_arg(ap, const gchar *);
	if(! val)  {
/* 	  *(*argv + *argc) = NULL; */
/* 	  g_strfreev(*argv); */
/* 	  return FALSE; */
	  continue;
	}
	*(*argv + *argc) = g_strdup_printf("%s=%s", key, val);
	(*argc)++;
	if(*argc + 1 ==	len)  {
	  *argv = g_renew(char *, *argv, len + __VEC_SECTOR);
	  len += __VEC_SECTOR;
	}
  }

  *(*argv + *argc) = NULL;

  return TRUE;
}


gchar *parse_arg(const gchar *key, gint argc, gchar **argv)
{
  gchar *val;
  gint len;

  if(! key || ! argv || ! argc)
	return NULL;

  len = strlen(key);
  while(argc--)  {
	if(! strncmp(key, *argv, len))  {
	  val = strchr(*argv, '=');
	  if(! val)
		continue;
	  return g_strdup(++val);
	}
	argv++;
  }

  return NULL;
}


gboolean     parse_arg_integer(const gchar *key, gint *val, gint argc, gchar **argv)
{
  gchar *p;
  gint len;

  if(! key || ! val || ! argv || ! argc)
	return FALSE;

  len = strlen(key);
  while(argc--)  {
	if(! strncmp(key, *argv, len))  {
	  p = strchr(*argv, '=');
	  if(! p)
		continue;
	  return sscanf(++p, "%d", val);
	}
	argv++;
  }

  return FALSE;
}


gboolean     parse_arg_float(const gchar *key, gfloat *val, gint argc, gchar **argv)
{
  gchar *p;
  gint len;

  if(! key || ! val || ! argv || ! argc)
	return FALSE;

  len = strlen(key);
  while(argc--)  {
	if(! strncmp(key, *argv, len))  {
	  p = strchr(*argv, '=');
	  if(! p)
		continue;
	  return sscanf(++p, "%f", val);
	}
	argv++;
  }

  return FALSE;
}


gboolean     parse_arg_string(const gchar *key, gchar **val, gint argc, gchar **argv)
{
  gchar *p;
  gint len;

  if(! key || ! val || ! argv || ! argc)
	return FALSE;

  len = strlen(key);
  while(argc--)  {
	if(! strncmp(key, *argv, len))  {
	  p = strchr(*argv, '=');
	  if(! p)
		continue;
	  *val = g_strdup(++p);
	  return TRUE;
	}
	argv++;
  }

  return FALSE;
}


static  gchar *__end_args(gint len, gchar *args)
{
  if(len <= 0)
	return NULL;
  for(;len > 0; len--)  {
	if(! *args)
	  if(! *(args + 1))
		return args + 1;
	args++;
  }

  return NULL;
}

gboolean build_arg_str(gint len, gchar **args, ...)
{
  va_list ap;
  gchar *end;
  const gchar *key, *value;
  gint offset, buf_len = 0;
  gint key_len, value_len;

  if(! args)
	return FALSE;

  if(*args)  {
	end = __end_args(len, *args);
	if(! end)
	  return FALSE;
	offset = end - *args;
	buf_len = len;
  }else  {
	*args = g_new0(gchar, 1024);
	offset = 0;
	end = *args;
	buf_len += 1024;
  }

  va_start(ap, args);
  while(key = va_arg(ap, const gchar *))  {
	value = va_arg(ap, const gchar *);
	if(! value)  {
/* 	  g_free(*args); */
#ifndef NDEBUG
	  print_warn("NULL value\n");
#endif
/* 	  *args = NULL; */
/* 	  return FALSE; */
	  continue;
	}
	
	key_len = strlen(key);
	value_len = strlen(value);
	while((key_len + value_len + 2) >= (buf_len - offset))  {
	  *args = g_renew(char, *args, buf_len + 1024);
	  buf_len += 1024;
	  end = *args + offset;
	}

	strcpy(end, key);
	end += key_len;
	*end = '=';
	end++;
	strcpy(end, value);
	end += value_len;
	*end = '\0';
	end++;
  }
  *end = '\0';

  return TRUE;
}


gchar       *parse_arg_str(const gchar *key, const gchar *args)
{
  const  gchar *value, *start = args;
  gint l;

  if(! key || ! args || ! *args)
	return NULL;
  l = strlen(key);

  while(strncmp(key, start, l))  {
	while(*++start);
	if(! *++start)
	  return NULL;
  }

  value = strchr(start, '=');
  if(! value)
	return NULL;

  return strdup(++value);
}


gboolean     parse_arg_str_integer(const gchar *key, gint *val, const gchar *args)
{
  const  gchar *value, *start = args;
  gint l;

  if(! key || ! val || ! args || ! *args)
	return FALSE;
  l = strlen(key);

  while(strncmp(key, start, l))  {
	while(*++start);
	if(! *++start)
	  return FALSE;
  }

  value = strchr(start, '=');
  if(! value)
	return FALSE;

  return sscanf(++value, "%d", val);

}


gboolean     parse_arg_str_float(const gchar *key, gfloat *val, const gchar *args)
{
  const  gchar *value, *start = args;
  gint l;

  if(! key || ! val || ! args || ! *args)
	return FALSE;
  l = strlen(key);

  while(strncmp(key, start, l))  {
	while(*++start);
	if(! *++start)
	  return FALSE;
  }

  value = strchr(start, '=');
  if(! value)
	return FALSE;

  return sscanf(++value, "%f", val);
}


gboolean     parse_arg_str_string(const gchar *key, gchar **val, const gchar *args)
{
  const  gchar *value, *start = args;
  gint l;

  if(! key || ! val || ! args || ! *args)
	return FALSE;
  l = strlen(key);

  while(strncmp(key, start, l))  {
	while(*++start);
	if(! *++start)
	  return FALSE;
  }

  value = strchr(start, '=');
  if(! value)
	return FALSE;

  return (*val = strdup(++value)) != NULL;

}


gboolean    build_arg_to_str(gint argc, gchar **argv, gchar **args)
{
  gint len, offset, key_len, value_len;
  gchar *key, *value, *end;

  if(! argv || ! args || argc < 0)
	return FALSE;
  if(argc == 0)
	*args = NULL;

  *args = g_new0(char, 1024);
  end = *args;
  len = 1024;

  for(; argc--; argv++)  {
	key = *argv;
	value = strchr(key, '=');
	if(! value || ! *(++value))  {
#ifndef NDEBUG
	  printf("** NULL value, ignored\n");
#endif
	  continue;
	}
	
	key_len = strlen(key);
	value_len = strlen(value);
	while((key_len + value_len + 2) >= (len - offset))  {
	  *args = g_renew(char, *args, len + 1024);
	  len += 1024;
	  end = *args + offset;
	}

	strcpy(end, key);
	end += key_len;
	*end = '=';
	end++;
	strcpy(end, value);
	end += value_len;
	*end = '\0';
	end++;
  }
  *end = '\0';

  return TRUE;
}


gboolean    build_arg_from_str(gint *argc, gchar ***argv, const gchar *args)
{
  gint i = 0, len;

  if(! argc || ! argv )
	return FALSE;
  if(! args || ! *args)  {
	*argc = 0;
	*argv = NULL;
	return TRUE;
  }

  *argv = g_new0(char *, 20);
  len = 20;
  while(*args)  {
	if(i == len)  {
	  *argv = g_renew(char *, *argv, len + 20);
	  len += 20;
	}
	*(*argv + i++) = g_strdup(args);
	args++;
  }
  *argc = i;

  return TRUE;
}

/***************** ARGPROC_TEST ************************/

#ifdef ARGPROC_TEST

int main(int argc, char **argv)
{
  float f;

  printf("xxx=:%s\n", parse_arg("xxx", argc, argv));

  build_arg(&argc, &argv, "yyy", "abc", "zzzz", "12345", "ffff", "3.1415", NULL);

  if(parse_arg_float("ffff", &f, argc, argv))
	printf("ffff=:%f\n", f);
  else
	printf("** Failed parse_arg_float.\n");

  g_strfreev(argv);

  puts("TEST OF STRING ARGS");  /* TEST OF STRING ARGS  */

  gchar *args = NULL;
  build_arg_str(0, &args, "abc", "123", "x", "1", "qin", "3.1415", NULL);

  printf("qin=:%s\n", parse_arg_str("qin", args));

  if(parse_arg_str_float("qin", &f, args))
	printf("float qin=:%f\n", f);
  else
	printf("** Failed parse_arg_float.\n");

  g_free(args);



  return 0;
}

#endif
